package com.lg.edu.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Component
@RefreshScope
public class IPExplosionProofBrushFilter implements GlobalFilter, Ordered {

    @Value("${ip.explosion.x}")
    private Integer x;

    @Value("${ip.explosion.y}")
    private Integer y;

    private static Map<String, List<Long>> IP_REGISTER_CACHE = new HashMap<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 思路：获取客户端ip，判断是否在黑名单中，在的话就拒绝访问，不在的话就放行
        // 从上下文中取出request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String requestPath = request.getPath().toString();
        // 仅对注册接口进行IP注册次数控制
        if (!requestPath.contains("/user/register")) {
            return chain.filter(exchange);
        }

        // 从request对象中获取客户端ip
        String clientIp = request.getRemoteAddress().getHostString();

        if (!IP_REGISTER_CACHE.containsKey(clientIp)) {
            ArrayList<Long> cacheList = new ArrayList<>();
            IP_REGISTER_CACHE.put(clientIp, cacheList);
        }

        List<Long> cacheList = IP_REGISTER_CACHE.get(clientIp);

        // 首先增加本次调用
        cacheList.add(System.currentTimeMillis());

        if (isBeyond(x, y, clientIp, cacheList)) {
            log.info("=====> IP[{}]访问过于频繁，暂拒绝该IP访问！", clientIp);
            String data = "IP[" + clientIp + "] access is too frequent, the IP access is temporarily denied!";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            response.setStatusCode(HttpStatus.SEE_OTHER);
            return response.writeWith(Mono.just(wrap));
        }

        return chain.filter(exchange);

        /*
        // 拿着clientIp去黑名单中查询，存在的话就决绝访问
        if(blackList.contains(clientIp)) {
            // 决绝访问，返回
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
            log.debug("=====>IP:" + clientIp + " 在黑名单中，将被拒绝访问！");
            String data = "Request be denied!";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        }

        // 合法请求，放行，执行后续的过滤器
        return chain.filter(exchange);
        */
    }


    /**
     * 返回值表示当前过滤器的顺序(优先级)，数值越小，优先级越高
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }

    private Boolean isBeyond(Integer minutesX, Integer limitY, String clientIp, List<Long> timestampList) {
        final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");

        long now = System.currentTimeMillis();
        long milliseconds = minutesX * 60 * 1000;

        long count = timestampList.stream()
                .filter(e -> {
                    log.info("当前时间:{}， 缓存时间：{}",
                            format.format(new Date(now)),
                            format.format(new Date(e)));
                    return now - e < milliseconds;
                })
                .count();

        log.info("======> IP[{}]最近{}分钟已调用注册接口{}次[max={}]", clientIp, minutesX, count, limitY);

        return count > limitY;
    }
}
